package com.vista.questionnaire.service;


import com.vista.questionnaire.domain.*;
import com.vista.questionnaire.domain.enumeration.QuestionEnum;
import com.vista.questionnaire.exception.BizException;
import com.vista.questionnaire.exception.ErrorDescriptor;
import com.vista.questionnaire.repository.AnswerDetailRepository;
import com.vista.questionnaire.repository.AnswerRepository;
import com.vista.questionnaire.repository.ExaminationRepository;
import com.vista.questionnaire.repository.QuestionRepository;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.OutputStream;
import java.util.*;

import static com.vista.questionnaire.domain.ParamsContents.*;

@Service
public class AnswerPOIExport {
    private final AnswerDetailRepository answerDetailRepository;
    private final AnswerRepository answerRepository;
    private final QuestionRepository questionRepository;
    private final ExaminationRepository examinationRepository;

    public AnswerPOIExport(AnswerDetailRepository answerDetailRepository, AnswerRepository answerRepository, QuestionRepository questionRepository, ExaminationRepository examinationRepository) {
        this.answerDetailRepository = answerDetailRepository;
        this.answerRepository = answerRepository;
        this.questionRepository = questionRepository;
        this.examinationRepository = examinationRepository;
    }

    public void export(OutputStream outputStream, Examination examination) throws IOException {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet();
        List<POITitle> poiTitles = this.getTitles(examination);
        sheet = writeTitles(poiTitles, sheet);
        this.writeAnswerDetails(sheet, this.answerRepository.findAllByExamination(examination), poiTitles);
//        FileOutputStream fos = new FileOutputStream("C:\\Users\\weare\\Desktop\\测试的Excel.xlsx");
//        workbook.write(fos);
//        fos.close();
        workbook.write(outputStream);
        outputStream.close();
    }

    private void writeAnswerDetails(Sheet sheet, List<Answer> answers, List<POITitle> poiTitles) {
        answers.forEach(answer -> {
            List<AnswerDetail> details = answer.getAnswerDetails();
            Row row = sheet.createRow(answers.indexOf(answer) + 2);
            details.sort(Comparator.comparingInt(o -> o.getQuestion().getIndexInExamination()));
            details.forEach(answerDetail -> {
                Question question = answerDetail.getQuestion();
                if (question.getType() == QuestionEnum.TEXT) {
                    Cell cell = row.createCell(poiTitles.indexOf(poiTitles.stream().filter(poiTitle ->
                        poiTitle.getQuestion().getId().equals(question.getId())
                    ).findFirst().get()));
                    cell.setCellValue(answerDetail.getValue());
                } else if (question.getType() == QuestionEnum.RADIO) {
                    Cell cell = row.createCell(getWriteIndex(poiTitles, question, answerDetail.getValue())
                    );
                    cell.setCellValue(true);
                } else if (question.getType() == QuestionEnum.CHECKBOX) {
                    String[] ss = answerDetail.getValue().split(",");
                    for (String s : ss) {
                        Cell cell = row.createCell(getWriteIndex(poiTitles, question, s)
                        );
                        cell.setCellValue(1);
                    }
                }
            });
        });
    }

    private int getWriteIndex(List<POITitle> poiTitles, Question question, String s) {
        return poiTitles.indexOf(poiTitles.stream().filter(poiTitle ->
            poiTitle.getQuestion().getId().equals(question.getId())
                && poiTitle.getValue() != null
                && poiTitle.getValue().equals(s)
        ).findFirst().get());
    }


    private Sheet writeTitles(List<POITitle> poiTitles, Sheet sheet) {
        Row row0 = sheet.createRow(0);
        Row row1 = sheet.createRow(1);
        //对抬头再排序
        poiTitles.sort(Comparator.comparingInt(o -> o.getQuestion().getIndexInExamination()));
        //todo 考虑使用模式匹配或动态规划？
        //单元格范围 参数（int firstRow, int lastRow, int firstCol, int lastCol)
        //序号
        for (int i = 0; i < poiTitles.size(); ) {
            POITitle poiTitle = poiTitles.get(i);
            int maxSimNum = this.getMaxSimNum(poiTitles.indexOf(poiTitle), poiTitle.getTitle(), poiTitles);
            if (maxSimNum > 1) {
                CellRangeAddress cellRangeSort =
                    new CellRangeAddress(0, 0, i, i + maxSimNum - 1);
                sheet.addMergedRegion(cellRangeSort);
                Cell cell = row0.createCell(i);
                cell.setCellValue(poiTitle.getTitle());
                i += maxSimNum;
            } else {
                Cell cell = row0.createCell(i);
                cell.setCellValue(poiTitle.getTitle());
                i++;
            }

        }
        poiTitles.forEach(poiTitle -> {
            Cell cell = row1.createCell(poiTitles.indexOf(poiTitle));
            cell.setCellValue(poiTitle.getQuestionName());
        });

        return sheet;
    }

    private int getMaxSimNum(int startIndex, String s, List<POITitle> poiTitles) {
        for (int i = startIndex; i < poiTitles.size(); i++) {
            if (!poiTitles.get(i).getTitle().equals(s))
                return i - startIndex;
            if ((i == poiTitles.size() - 1) && poiTitles.get(i).getTitle().equals(s))
                return i - startIndex + 1;
        }
        return 1;
    }

    private List<POITitle> getTitles(Examination examination) {
        Document document = Jsoup.parse(examination.getContent());
        //这里需要保证导出的题目顺序和上传的题目顺序一样
        examination.getQuestions().sort(Comparator.comparingInt(Question::getIndexInExamination));
        List<POITitle> titles = new ArrayList<>();
        examination.getQuestions().forEach(question ->
            titles.addAll(Objects.requireNonNull(switchQuestion(question, document))));
        return titles;
    }

    private List<POITitle> switchQuestion(Question question, Document document) {
        switch (question.getType()) {
            case TEXT: {
                //矩阵填空题
                if (!StringUtils.isEmpty(question.getName())
                    && !StringUtils.isEmpty(question.getY())) {
                    return this.mutiText(question, document);
                }
                //单一填空题
                else if (question.getDocumentID().equals(question.getName())) {
                    return this.singleText(question, document);
                }
            }
            case RADIO:
                return this.checkBoxOrRadio(question, document);
            case CHECKBOX:
                return this.checkBoxOrRadio(question, document);
        }
        return null;
    }

    private List<POITitle> mutiText(Question question, Document document) {
        Elements elements = document.getElementsByAttributeValue(ID, question.getY());
        if (elements.size() < 1)
            throw new BizException(ErrorDescriptor.QuestionDupError);
        Element title = elements.get(0);

        List<POITitle> rtns = new ArrayList<>();
        Document inputsDoc = Jsoup.parse(question.getContent());
        Elements inputElements = inputsDoc.getElementsByAttributeValue(NAME, question.getName());
        if (inputElements.size() != 1)
            throw new BizException(ErrorDescriptor.QuestionDupError);
        POITitle rtn = new POITitle();
        rtn.setQuestion(question);
        rtn.setTitle(title.text());
        rtn.setQuestionName(inputElements.get(0).attributes().get(X));
        rtn.setName(question.getName());
        rtns.add(rtn);

        inputElements.forEach(element -> {

        });
        return rtns;
    }

    private List<POITitle> singleText(Question question, Document document) {
        POITitle rtn = new POITitle();
        Elements elements = document.getElementsByAttributeValue(FOR, question.getName());
        if (elements.size() != 1)
            throw new BizException(ErrorDescriptor.QuestionDupError);
        Element title = elements.get(0);
        rtn.setQuestion(question);
        rtn.setTitle(title.text());
        rtn.setName(question.getName());
        return Arrays.asList(rtn);
    }

    private List<POITitle> checkBoxOrRadio(Question question, Document document) {
        Elements elements = document.getElementsByAttributeValue(FOR, question.getName());
        if (elements.size() < 1)
            throw new BizException(ErrorDescriptor.QuestionDupError);
        Element title = elements.get(0);

        List<POITitle> rtns = new ArrayList<>();
        Elements inputElements = document.getElementsByAttributeValue(NAME, question.getName());

        inputElements.forEach(element -> {
            if (!element.parent().tagName().equals(LABEL))
                throw new BizException(ErrorDescriptor.DataLogicError);
            POITitle rtn = new POITitle();
            rtn.setQuestion(question);
            rtn.setTitle(title.text());
            rtn.setQuestionName(element.parent().text());
            rtn.setName(question.getName());
            rtn.setValue(element.attributes().get(VALUE));
            rtns.add(rtn);
        });
        return rtns;
    }


    private Element getFirstElementFromQuestion(Question question) {
        Elements elements = Jsoup.parse(question.getContent()).getAllElements();
        if (elements.size() == 0)
            throw new BizException(ErrorDescriptor.DataNotFoundError);
        else
            return elements.get(0).getElementsByTag(INPUT).get(0);

    }


}
